#ifdef MODE_OPENGL

#include "../../libPhysics/Physics.h"

#include <vector>
#include <string>
#include <iostream>
#include <fstream>

#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <IL/il.h>

#include <SDL/SDL.h>
#include <SDL/SDL_quit.h>

#include "graphics_OGL.h"

#define SHADERPATH ".\\res\\shaders\\"

using std::vector;
using std::list;
using std::string;
using std::wstring;

namespace Lib3D {

Graphics::Graphics(Level & level, LibPhysics::Physics & physics) : level(level), windowWidth(1024), windowHeight(768), physics(physics)
{
	SDL_WM_SetCaption("Projet RV", NULL);
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		printf("Unable to initialise SDL: %s\n", SDL_GetError());
	}
	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	SDL_Surface * screen = SDL_SetVideoMode(windowWidth, windowHeight, 16, SDL_OPENGL | SDL_HWSURFACE /*| SDL_FULLSCREEN*/);
	_putenv("SDL_VIDEO_WINDOW_POS=center");

	GLenum err = glewInit();
	if (err != GLEW_OK) {
		std::cout << "Unable to initialise GLEW" << std::endl;
	} else {
		std::cout << "GLEW initialised" << std::endl;
	}

	if (glewIsSupported("GL_VERSION_2_0")) {
		std::cout << "OpenGL 2.0 supported" << std::endl;
	} else {
		std::cout << "OpenGL 2.0 not supported" << std::endl;
		exit(1);
	}

	ilInit();

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glViewport(0, 0, windowWidth, windowHeight);

	//glEnable(GL_DEPTH_TEST);
    //glDepthMask(GL_TRUE);
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(90.0f, ((float) windowWidth)/((float) windowHeight), 1.f, 60.f);

	initHall();
	initObstacle();
	initPlayer();
	initInterface();
}

Graphics::~Graphics()
{
	glDeleteBuffers(1, &hallPositionsVBO);
	glDeleteBuffers(1, &hallColorsVBO);
	glDeleteBuffers(1, &hallIndicesVBO);
	glDeleteProgram(hallProgram);
	glDeleteShader(hallFragmentShader);
	glDeleteProgram(obstacleProgram);
	glDeleteShader(obstacleFragmentShader);
}

void   Graphics::NextFrame(){
	SDL_GL_SwapBuffers();
}  


void   Graphics::DrawPoint(float x, float y, float z){
	glColor3f(0,0,1);
	glPointSize(5);
	glBegin(GL_POINTS);
		glVertex3f(x,y,z);
	glEnd();
}
void   Graphics::DrawLine(float x1, float y1, float z1, float x2, float y2, float z2, float r, float g, float b){
	glColor3f(r,g,b);
	glBegin(GL_LINES);
		glVertex3f(x1,y1,z1);
		glVertex3f(x2,y2,z2);
	glEnd();
}


bool Graphics::initHall()
{
	std::string line;
	std::string fragmentShaderText;
	std::ifstream fragmentShaderFile(SHADERPATH"hall.frag");
	if (fragmentShaderFile.is_open()) {
		std::cout << "Fragment shader:" << std::endl;
		while (!fragmentShaderFile.eof()) {
			getline(fragmentShaderFile, line);
			std::cout << "\t" << line << std::endl;
			fragmentShaderText += line;
		}
		fragmentShaderFile.close();
	} else {
		std::cout << "Unable to open file" << std::endl;
	}

	hallFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	const char * text = fragmentShaderText.c_str();
	const GLint length = fragmentShaderText.size();
	glShaderSource(hallFragmentShader, 1, &text, &length);
	glCompileShader(hallFragmentShader);
	GLint success;
	glGetShaderiv(hallFragmentShader, GL_COMPILE_STATUS, &success);
	if (!success) {
		GLint infoLogLength;
		glGetShaderiv(hallFragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
		GLchar * infoLog = new GLchar[infoLogLength];
		glGetShaderInfoLog(hallFragmentShader, infoLogLength, NULL, infoLog);
		fprintf(stderr, "Error in fragment shader compilation!\n");
		fprintf(stderr, "Info log: %s\n", infoLog);
		delete [] infoLog;
	}

	hallProgram = glCreateProgram();
	glAttachShader(hallProgram, hallFragmentShader);
	glLinkProgram(hallProgram);
	glGetProgramiv(hallProgram, GL_LINK_STATUS, &success);
	if (!success) {
		GLint infoLogLength;
		glGetProgramiv(hallProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
		GLchar * infoLog = new GLchar[infoLogLength];
		glGetProgramInfoLog(hallProgram, infoLogLength, NULL, infoLog);
		fprintf(stderr, "Error in program linkage!\n");
		fprintf(stderr, "Info log: %s\n", infoLog);
		delete [] infoLog;
	}
	glValidateProgram(hallProgram);
	glGetProgramiv(hallProgram, GL_VALIDATE_STATUS, &success);
	if (!success) {
		GLint infoLogLength;
		glGetProgramiv(hallProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
		GLchar * infoLog = new GLchar[infoLogLength];
		glGetProgramInfoLog(hallProgram, infoLogLength, NULL, infoLog);
		fprintf(stderr, "Error in program linkage!\n");
		fprintf(stderr, "Info log: %s\n", infoLog);
		delete [] infoLog;
	}


	static const GLsizeiptr positionDataSize = 16 * 3 * sizeof(GLfloat);
	static const GLfloat positionData[] = 
	{
		// Left
		-1.0f,  1.0f,  0.0f,
		-1.0f,  1.0f, 50.0f,
		-1.0f, -1.0f, 50.0f,
		-1.0f, -1.0f,  0.0f,

		// Right
		 1.0f,  1.0f,  0.0f,
		 1.0f,  1.0f, 50.0f,
		 1.0f, -1.0f, 50.0f,
		 1.0f, -1.0f,  0.0f,

		// Up
		-1.0f,  1.0f,  0.0f,
		-1.0f,  1.0f, 50.0f,
		 1.0f,  1.0f, 50.0f,
		 1.0f,  1.0f,  0.0f,

		// Down
		-1.0f, -1.0f,  0.0f,
		-1.0f, -1.0f, 50.0f,
		 1.0f, -1.0f, 50.0f,
		 1.0f, -1.0f,  0.0f,
	};

	hallPositionsVBO = 0;
	glGenBuffers(1, &hallPositionsVBO);
	glBindBuffer(GL_ARRAY_BUFFER, hallPositionsVBO);
	glBufferData(GL_ARRAY_BUFFER, positionDataSize, positionData, GL_STATIC_DRAW);

	static const GLsizeiptr colorDataSize = 16 * 4 * sizeof(GLubyte);
	static const GLubyte colorData[] =
	{
		// Left
		255, 32, 32, 255,
		32, 32, 32, 255,
		32, 32, 32, 255,
		32, 32, 255, 255,

		// Right
		32, 255, 32, 255,
		32, 32, 32, 255,
		32, 32, 32, 255,
		255, 255, 32, 255,

		// Up
		255, 32, 32, 255,
		32, 32, 32, 255,
		32, 32, 32, 255,
		32, 255, 32, 255,

		// Down
		32, 32, 255, 255,
		32, 32, 32, 255,
		32, 32, 32, 255,
		255, 255, 32, 255,
	};

	hallColorsVBO = 0;
	glGenBuffers(1, &hallColorsVBO);
	glBindBuffer(GL_ARRAY_BUFFER, hallColorsVBO);
	glBufferData(GL_ARRAY_BUFFER, colorDataSize, colorData, GL_STATIC_DRAW);

	static const GLsizeiptr indicesDataSize = 10 * 3 * sizeof(GLuint);
	static const GLuint indicesData[] =
	{
		// Left
        0,1,3,
		1,2,3,

		// Top
		8,11,10,
		8,10,9,

		// Right
		4,6,5,
		4,7,6,

		// Bottom
		12,13,14,
		12,14,15,

		// End cap
		1,5,6,
		1,6,2,
	};
	hallIndicesCount = 30;

	hallIndicesVBO = 0;
	glGenBuffers(1, &hallIndicesVBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, hallIndicesVBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesDataSize, indicesData, GL_STATIC_DRAW);

	return true;
}

bool Graphics::initObstacle()
{
	std::string line;
	std::string fragmentShaderText;
	std::ifstream fragmentShaderFile(SHADERPATH"obstacle.frag");
	if (fragmentShaderFile.is_open()) {
		std::cout << "Fragment shader:" << std::endl;
		while (!fragmentShaderFile.eof()) {
			getline(fragmentShaderFile, line);
			std::cout << "\t" << line << std::endl;
			fragmentShaderText += line;
		}
		fragmentShaderFile.close();
	} else {
		std::cout << "Unable to open file" << std::endl;
	}

	obstacleFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	const char * text = fragmentShaderText.c_str();
	const GLint length = fragmentShaderText.size();
	glShaderSource(obstacleFragmentShader, 1, &text, &length);
	glCompileShader(obstacleFragmentShader);
	GLint success;
	glGetShaderiv(obstacleFragmentShader, GL_COMPILE_STATUS, &success);
	if (!success) {
		GLint infoLogLength;
		glGetShaderiv(obstacleFragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
		GLchar * infoLog = new GLchar[infoLogLength];
		glGetShaderInfoLog(obstacleFragmentShader, infoLogLength, NULL, infoLog);
		fprintf(stderr, "Error in fragment shader compilation!\n");
		fprintf(stderr, "Info log: %s\n", infoLog);
		delete [] infoLog;
	}

	obstacleProgram = glCreateProgram();
	glAttachShader(obstacleProgram, obstacleFragmentShader);
	glLinkProgram(obstacleProgram);
	glGetProgramiv(obstacleProgram, GL_LINK_STATUS, &success);
	if (!success) {
		GLint infoLogLength;
		glGetProgramiv(obstacleProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
		GLchar * infoLog = new GLchar[infoLogLength];
		glGetProgramInfoLog(obstacleProgram, infoLogLength, NULL, infoLog);
		fprintf(stderr, "Error in program linkage!\n");
		fprintf(stderr, "Info log: %s\n", infoLog);
		delete [] infoLog;
	}
	glValidateProgram(obstacleProgram);
	glGetProgramiv(obstacleProgram, GL_VALIDATE_STATUS, &success);
	if (!success) {
		GLint infoLogLength;
		glGetProgramiv(obstacleProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
		GLchar * infoLog = new GLchar[infoLogLength];
		glGetProgramInfoLog(obstacleProgram, infoLogLength, NULL, infoLog);
		fprintf(stderr, "Error in program linkage!\n");
		fprintf(stderr, "Info log: %s\n", infoLog);
		delete [] infoLog;
	}

	return true;
}

void Graphics::Draw()
{
	glClearColor(0.0f, 0.125f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.2f, 0.3f, -1.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
 
	drawHall();
	glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
	DrawLine(-1.0f, -1.0f, 0.0f, -1.0f, -1.0f, 50.0f, 0,0,1);
	DrawLine( 1.0f, -1.0f, 0.0f,  1.0f, -1.0f, 50.0f, 0,0,1);
	DrawLine( 1.0f,  1.0f, 0.0f,  1.0f,  1.0f, 50.0f, 0,0,1);
	DrawLine(-1.0f,  1.0f, 0.0f, -1.0f,  1.0f, 50.0f, 0,0,1);
	drawObstacles();
	//drawPlayer();
	drawInterface();
}

void Graphics::drawHall()
{
	glBindBuffer(GL_ARRAY_BUFFER, hallPositionsVBO);
	glVertexPointer(3, GL_FLOAT, 0, 0);
	glBindBuffer(GL_ARRAY_BUFFER, hallColorsVBO);
	glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, hallIndicesVBO);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glDrawElements(GL_TRIANGLES, hallIndicesCount, GL_UNSIGNED_INT, 0);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
}

void Graphics::drawObstacles()
{
	vector<Obstacle*> obs;
	for(Song::Iterator tempIt = level.songIterator ; tempIt != Song::Iterator::end() && tempIt.getPosition() < (int) level.levelPosition + level.displayedDuration ; ++tempIt) {
		obs.push_back(*tempIt);
	}
	for(vector<Obstacle*>::reverse_iterator it = obs.rbegin() ; it != obs.rend() ; ++it) {
		Obstacle * obstacle = *it;
		int time = obstacle->getTime();

		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glTranslatef(0.0f, 0.0f, (time - level.levelPosition) / 1000.0f);

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
		
		glBegin(GL_QUADS);

		float length = obstacle->getDuration() / 1000.0f;
		if(obstacle->getDuration() > 0) {
			switch(obstacle->getType()) {
				case Obstacle::Top:
					glVertex3f( 1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
					glVertex3f( 1.0f, 1.0f - (obstacle->getSize1() / 100.0f), length);
					glVertex3f(-1.0f, 1.0f - (obstacle->getSize1() / 100.0f), length);
					glVertex3f(-1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
					break;
				case Obstacle::Bottom:
					glVertex3f( 1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
					glVertex3f( 1.0f,-1.0f + (obstacle->getSize1() / 100.0f), length);
					glVertex3f(-1.0f,-1.0f + (obstacle->getSize1() / 100.0f), length);
					glVertex3f(-1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
					break;
				case Obstacle::Right:
					glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f), 1.0f, length);
					glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f),-1.0f, length);
					glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
					glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
					break;
				case Obstacle::Left:
					glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f), 1.0f, length);
					glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f),-1.0f, length);
					glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
					glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
					break;
			}
		}
		
		Color color = obstacle->getColor();
		glColor4ub(color.r, color.g, color.b, 204);

		switch(obstacle->getType()) {
			case Obstacle::Top:
				glVertex3f( 1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
				glVertex3f( 1.0f, 1.0f, 0.0f);
				glVertex3f(-1.0f, 1.0f, 0.0f);
				glVertex3f(-1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
				break;
			case Obstacle::Bottom:
				glVertex3f( 1.0f,-1.0f, 0.0f);
				glVertex3f( 1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
				glVertex3f(-1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
				glVertex3f(-1.0f,-1.0f, 0.0f);
				break;
			case Obstacle::Right:
				glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
				glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
				glVertex3f(-1.0f,-1.0f, 0.0f);
				glVertex3f(-1.0f, 1.0f, 0.0f);
				break;
			case Obstacle::Left:
				glVertex3f( 1.0f, 1.0f, 0.0f);
				glVertex3f( 1.0f,-1.0f, 0.0f);
				glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
				glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
				break;
		}
		glEnd();

		glPopMatrix();

		bool found = false;
		for(list<Obstacle*>::const_iterator itCropped = croppedObstacles.begin() ; itCropped != croppedObstacles.end() && !found ; ++itCropped) {
			if(*itCropped == obstacle) {
				found = true;
			}
		}
		if(!found) {
			croppedObstacles.push_back(obstacle);
		}
	}

	for(list<Obstacle*>::iterator it = croppedObstacles.begin() ; it != croppedObstacles.end() ; ) {
		Obstacle * obstacle = *it;
		if(obstacle->getTime() + obstacle->getDuration() <= (int) level.levelPosition) {
			it = croppedObstacles.erase(it);
		} else {
			if(obstacle->getTime() < (int) level.levelPosition) {
				glMatrixMode(GL_MODELVIEW);
				glPushMatrix();

				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

				glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
				
				glBegin(GL_QUADS);

				float length = (obstacle->getDuration() + obstacle->getTime() - level.levelPosition) / 1000.0f;
				if(obstacle->getDuration() > 0) {
					switch(obstacle->getType()) {
						case Obstacle::Top:
							glVertex3f( 1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
							glVertex3f( 1.0f, 1.0f - (obstacle->getSize1() / 100.0f), length);
							glVertex3f(-1.0f, 1.0f - (obstacle->getSize1() / 100.0f), length);
							glVertex3f(-1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
							break;
						case Obstacle::Bottom:
							glVertex3f( 1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
							glVertex3f( 1.0f,-1.0f + (obstacle->getSize1() / 100.0f), length);
							glVertex3f(-1.0f,-1.0f + (obstacle->getSize1() / 100.0f), length);
							glVertex3f(-1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
							break;
						case Obstacle::Right:
							glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f), 1.0f, length);
							glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f),-1.0f, length);
							glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
							glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
							break;
						case Obstacle::Left:
							glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f), 1.0f, length);
							glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f),-1.0f, length);
							glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
							glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
							break;
					}
				}
				
				
				Color color = obstacle->getColor();
				glColor4ub(color.r, color.g, color.b, 204);

				switch(obstacle->getType()) {
					case Obstacle::Top:
						glVertex3f( 1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
						glVertex3f( 1.0f, 1.0f, 0.0f);
						glVertex3f(-1.0f, 1.0f, 0.0f);
						glVertex3f(-1.0f, 1.0f - (obstacle->getSize1() / 100.0f), 0.0f);
						break;
					case Obstacle::Bottom:
						glVertex3f( 1.0f,-1.0f, 0.0f);
						glVertex3f( 1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
						glVertex3f(-1.0f,-1.0f + (obstacle->getSize1() / 100.0f), 0.0f);
						glVertex3f(-1.0f,-1.0f, 0.0f);
						break;
					case Obstacle::Right:
						glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
						glVertex3f(-1.0f + (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
						glVertex3f(-1.0f,-1.0f, 0.0f);
						glVertex3f(-1.0f, 1.0f, 0.0f);
						break;
					case Obstacle::Left:
						glVertex3f( 1.0f, 1.0f, 0.0f);
						glVertex3f( 1.0f,-1.0f, 0.0f);
						glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f),-1.0f, 0.0f);
						glVertex3f( 1.0f - (obstacle->getSize1() / 100.0f), 1.0f, 0.0f);
						break;
				}
				glEnd();

				glPopMatrix();
			}
			
			++it;
		}
	}
}

#include <Windows.h>
#include <shlwapi.h>
void Graphics::initPlayer()
{
	for(int i = 0 ; i < 3 ; i++) {
		playerCylinders[i] = gluNewQuadric();
		gluQuadricDrawStyle(playerCylinders[i], GLU_LINE); // GLU_FILL GLU_LINE
		gluQuadricNormals(playerCylinders[i], GLU_SMOOTH);
		gluQuadricTexture(playerCylinders[i], GL_TRUE);
	}
}

void Graphics::drawPlayer()
{
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	//glTranslatef(0.0f, 0.0f, 5.0f);
	float * m = physics.getBoneTransform(2);
	//glMultMatrixf(m);
	glLoadMatrixf(m);

	//glDisable(GL_DEPTH_TEST);
	//glEnable(GL_TEXTURE_2D);
	glEnable(GL_DEPTH_TEST);

	float s = physics.getBoneYScale(0);
	//gluCylinder(playerCylinders[0], 0.2f, 0.2f, s, 12, 12);
	gluSphere(playerCylinders[0], 1, 12, 12);
	
	glPopMatrix();
}


void Graphics::initInterface()
{

	string lifeTexturePath("./res/life.png");
	wstring wlifeTexturePath = std::wstring(lifeTexturePath.begin(), lifeTexturePath.end());
	lifeTexture = loadTexture(wlifeTexturePath, true);

	string lifeMeterTexturePath("./res/lifeMeter.png");
	wstring wlifeMeterTexturePath = std::wstring(lifeMeterTexturePath.begin(), lifeMeterTexturePath.end());
	lifeMeterTexture = loadTexture(wlifeMeterTexturePath, false);

	string gameOverTexturePath("./res/gameOver.png");
	wstring wgameOverTexturePath = std::wstring(gameOverTexturePath.begin(), gameOverTexturePath.end());
	gameOverTexture = loadTexture(wgameOverTexturePath, true);
}


void Graphics::drawInterface()
{
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0.0, windowWidth, 0.0, windowHeight, -1.0, 1.0);
	
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);

	drawLife();

	if(level.getState() == Level::GAMEOVER) {
		drawGameOver();
	}

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}


void Graphics::drawLife()
{
	
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
	glEnable(GL_TEXTURE_2D);
	
	float lifeRatio = ((float) level.getLife()) / ((float) level.getLifeMax());
	glBindTexture(GL_TEXTURE_2D, lifeMeterTexture);
	glBegin(GL_QUADS);
	glTexCoord2d(1.0,1.0); glVertex2f(120.0f, (windowHeight - 600.0f) / 2.0f);
	glTexCoord2d(1.0,1.0 - lifeRatio); glVertex2f(120.0f, ((windowHeight - 600.0f) / 2.0f + 600.0f * lifeRatio));
	glTexCoord2d(0.0,1.0 - lifeRatio); glVertex2f(20.0f, ((windowHeight - 600.0f) / 2.0f + 600.0f * lifeRatio));
	glTexCoord2d(0.0,1.0); glVertex2f(20.0f, (windowHeight - 600.0f) / 2.0f);
	glEnd();

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBindTexture(GL_TEXTURE_2D, lifeTexture);
	glBegin(GL_QUADS);
	glTexCoord2d(1.0,1.0); glVertex2f(120.0f, (windowHeight - 600.0f) / 2.0f);
	glTexCoord2d(1.0,0.0); glVertex2f(120.0f, (windowHeight - 600.0f) / 2.0f + 600.0f);
	glTexCoord2d(0.0,0.0); glVertex2f(20.0f, (windowHeight - 600.0f) / 2.0f + 600.0f);
	glTexCoord2d(0.0,1.0); glVertex2f(20.0f, (windowHeight - 600.0f) / 2.0f);
	glEnd();
	glBindTexture(GL_TEXTURE_2D, 0);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
}


void Graphics::drawGameOver()
{
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBindTexture(GL_TEXTURE_2D, gameOverTexture);
	glBegin(GL_QUADS);
	glTexCoord2d(1.0,1.0); glVertex2f((windowWidth - 400.0f) / 2.0f + 400.0f, (windowHeight - 400.0f) / 2.0f);
	glTexCoord2d(1.0,0.0); glVertex2f((windowWidth - 400.0f) / 2.0f + 400.0f, (windowHeight - 400.0f) / 2.0f + 400.0f);
	glTexCoord2d(0.0,0.0); glVertex2f((windowWidth - 400.0f) / 2.0f, (windowHeight - 400.0f) / 2.0f + 400.0f);
	glTexCoord2d(0.0,1.0); glVertex2f((windowWidth - 400.0f) / 2.0f, (windowHeight - 400.0f) / 2.0f);
	glEnd();
	glBindTexture(GL_TEXTURE_2D, 0);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
}


int Graphics::loadTexture(wstring & path, bool alpha)
{
	ILuint texID;
	GLuint image;
	ilGenImages(1, &texID);
	ilBindImage(texID);
	if(ilLoadImage(path.c_str())) {
		if(ilConvertImage((alpha ? IL_RGBA : IL_RGB), IL_UNSIGNED_BYTE)) {
			glGenTextures(1, &image);
			glBindTexture(GL_TEXTURE_2D, image);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D, 0, (alpha ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT) /*ilGetInteger(IL_IMAGE_BPP)*/,
				  ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT),
				  0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE,
			      ilGetData());
		} else {
			std::cout << "Unable to convert texture \"" << path.c_str() << std::endl;
			return 0;
		}
	} else {
		std::cout << "Unable to load texture \"" << path.c_str() << std::endl;
		return 0;
	}
	ilDeleteImages(1, &texID);

	std::cout << "Texture loaded : \"" << path.c_str() << "\" " << image << std::endl;

	glBindTexture(GL_TEXTURE_2D, 0);

	return image;  // Return texture index
}

}

#endif // MODE_OPENGL
